home *** CD-ROM | disk | FTP | other *** search
/ PCGUIA 117 / PC Guia 117.iso / Software / Utils / Software2 / Product11 / Setup.exe / MT-3.16-full-en_US / php / mt.php
PHP Script  |  2005-03-21  |  21KB  |  579 lines

  1. <?php
  2. # Copyright 2001-2005 Six Apart. This code cannot be redistributed without
  3. # permission from www.movabletype.org.
  4. #
  5. # $Id: mt.php 10538 2005-03-21 19:31:23Z bchoate $
  6.  
  7. define('VERSION', '3.16');
  8.  
  9. class MT {
  10.     var $mime_types = array(
  11.         '__default__' => 'text/html',
  12.         'css' => 'text/css',
  13.         'txt' => 'text/plain',
  14.         'rdf' => 'text/xml',
  15.         'rss' => 'text/xml',
  16.         'xml' => 'text/xml',
  17.     );
  18.     var $blog_id;
  19.     var $db;
  20.     var $config;
  21.     var $debugging = false;
  22.     var $caching = false;
  23.     var $conditional = false;
  24.     var $log = array();
  25.     var $id;
  26.     var $request;
  27.     var $http_error;
  28.  
  29.     /***
  30.      * Constructor for MT class. Also declares a global variable
  31.      * '$mt' and assigns itself to that. There can only be one
  32.      * instance of this class.
  33.      */
  34.     function MT($blog_id = null, $cfg_file = null) {
  35.         global $mt;
  36.         if (isset($mt)) {
  37.             die("Only one instance of the MT class can be created.");
  38.         }
  39.         $mt = $this;
  40.         $this->id = md5(uniqid('MT',true));
  41.  
  42.         if (!isset($cfg_file)) {
  43.             $mtdir = dirname(dirname(__FILE__));
  44.             $cfg_file = $mtdir . DIRECTORY_SEPARATOR . "mt.cfg";
  45.         }
  46.  
  47.         $this->configure($cfg_file);
  48.         if (isset($blog_id)) {
  49.             $this->blog_id = $blog_id;
  50.         }
  51.     }
  52.  
  53.     function init_plugins() {
  54.         $plugin_dir = $this->config['PHPDir'] . DIRECTORY_SEPARATOR . 'plugins';
  55.         $ctx =& $this->context();
  56.         // global filters have to be handled differently from
  57.         // tag attributes, so this causes them to be recognized
  58.         // as they should...
  59.         if (is_dir($plugin_dir)) {
  60.             if ($dh = opendir($plugin_dir)) {
  61.                  while (($file = readdir($dh)) !== false) {
  62.                      if (preg_match('/^modifier\.(.+?)\.php$/', $file, $matches)) {
  63.                          $ctx->add_global_filter($matches[1]);
  64.                      } elseif (preg_match('/^init\.(.+?)\.php$/', $file, $matches)) {
  65.                          // load 'init' plugin file
  66.                          require_once($file);
  67.                      }
  68.                  }
  69.                  closedir($dh);
  70.              }
  71.         }
  72.     }
  73.  
  74.     /***
  75.      * Retreives a handle to the database and assigns it to
  76.      * the member variable 'db'.
  77.      */
  78.     function &db() {
  79.         if (isset($this->db)) return $this->db;
  80.  
  81.         require_once("mtdb_".$this->config['DBDriver'].".php");
  82.         $mtdbclass = 'MTDatabase_'.$this->config['DBDriver'];
  83.         $this->db = new $mtdbclass($this->config['DBUser'],
  84.             $this->config['DBPassword'], $this->config['Database'],
  85.             $this->config['DBHost']);
  86.         return $this->db;
  87.     }
  88.  
  89.     /***
  90.      * Loads configuration data from mt.cfg and mt-db-pass.cgi files.
  91.      * Stores content in the 'config' member variable.
  92.      */
  93.     function configure($file = null) {
  94.         if (isset($this->config)) return $config;
  95.  
  96.         $cfg = array();
  97.         if ($fp = file($file)) {
  98.             foreach ($fp as $line) {
  99.                 // search through the file
  100.                 if (!ereg('^\s*\#',$line)) {
  101.                     // ignore lines starting with the hash symbol
  102.                     if (preg_match('/^\s*([^ ]+)[ ](.*)(\r|n)?$/', $line, $regs)) {
  103.                         $key = trim($regs[1]);
  104.                         $value = trim($regs[2]);
  105.                         $cfg[$key] = $value;
  106.                     }
  107.                 }
  108.             }
  109.         } else {
  110.             die("Unable to open configuration file $file");
  111.         }
  112.  
  113.         // setup directory locations
  114.         // location of mt.php
  115.         $cfg['PHPDir'] = realpath(dirname(__FILE__));
  116.         // path to MT directory
  117.         $cfg['MTDir'] = realpath(dirname($file));
  118.         // path to handlers
  119.         $cfg['PHPLibDir'] = $cfg['PHPDir'] . DIRECTORY_SEPARATOR . 'lib';
  120.  
  121.         // assign defaults:
  122.         isset($cfg['StaticWebPath']) or
  123.             $cfg['StaticWebPath'] = $cfg['CGIPath'];
  124.         isset($cfg['PublishCharset']) or
  125.             $cfg['PublishCharset'] = 'iso-8859-1';
  126.         isset($cfg['TrackbackScript']) or
  127.             $cfg['TrackbackScript'] = 'mt-tb.cgi';
  128.         isset($cfg['CommentScript']) or
  129.             $cfg['CommentScript'] = 'mt-comments.cgi';
  130.         isset($cfg['XMLRPCScript']) or
  131.             $cfg['XMLRPCScript'] = 'mt-xmlrpc.cgi';
  132.         isset($cfg['SearchScript']) or
  133.             $cfg['SearchScript'] = 'mt-search.cgi';
  134.         isset($cfg['DefaultLanguage']) or
  135.             $cfg['DefaultLanguage'] = 'en_us';
  136.         isset($cfg['GlobalSanitizeSpec']) or
  137.             $cfg['GlobalSanitizeSpec'] = 'a href,b,i,br/,p,strong,em,ul,ol,blockquote,pre';
  138.         isset($cfg['CGIPath']) or
  139.             $cfg['CGIPath'] = 'cgi-bin';
  140.         isset($cfg['SignOnURL']) or
  141.             $cfg['SignOnURL'] = 'https://www.typekey.com/t/typekey/login?';
  142.         isset($cfg['SignOffURL']) or
  143.             $cfg['SignOffURL'] = 'https://www.typekey.com/t/typekey/logout?';
  144.         isset($cfg['IdentityURL']) or
  145.             $cfg['IdentityURL'] = 'http://profile.typekey.com/';
  146.         isset($cfg['PublishCommenterIcon']) or
  147.             $cfg['PublishCommenterIcon'] = '1';
  148.     
  149.         $cfg['DBHost'] or $cfg['DBHost'] = 'localhost'; // default to localhost
  150.         $driver = $cfg['ObjectDriver'];
  151.         $driver = preg_replace('/^DBI::/', '', $driver);
  152.         $driver or $driver = 'mysql';
  153.         $cfg['DBDriver'] = $driver;
  154.     
  155.         if ((strlen($cfg['Database'])<1 || strlen($cfg['DBUser'])<1)) {
  156.             if ($driver != 'sqlite') {
  157.                 die("Unable to read database or username");
  158.             }
  159.         }
  160.     
  161.         // read in the database password
  162.         $password = implode('', file($cfg['MTDir'] . DIRECTORY_SEPARATOR . 'mt-db-pass.cgi'));
  163.         $password = trim($password, "\n\r\0");
  164.         $cfg['DBPassword'] = $password;
  165.  
  166.         // set up include path
  167.         // add MT-PHP 'plugins' and 'lib' directories to the front
  168.         // of the existing PHP include path:
  169.         if (strtoupper(substr(PHP_OS, 0,3) == 'WIN')) {
  170.             $path_sep = ';';
  171.         } else {
  172.             $path_sep = ':';
  173.         }
  174.         ini_set('include_path',
  175.             $cfg['PHPDir'] . DIRECTORY_SEPARATOR . "plugins" . $path_sep .
  176.             $cfg['PHPDir'] . DIRECTORY_SEPARATOR . "lib" . $path_sep .
  177.             $cfg['PHPDir'] . DIRECTORY_SEPARATOR . "extlib" . $path_sep .
  178.             $cfg['PHPDir'] . DIRECTORY_SEPARATOR . "extlib" . DIRECTORY_SEPARATOR . "smarty" . $path_sep .
  179.             ini_get('include_path')
  180.         );
  181.     
  182.         $this->config =& $cfg;
  183.     }
  184.  
  185.     function configure_paths($blog_site_path) {
  186.         if (preg_match('/^\./', $blog_site_path)) {
  187.             // relative address, so tack on the MT dir in front
  188.             $blog_site_path = $this->config['MTDir'] .
  189.                 DIRECTORY_SEPARATOR . $blog_site_path;
  190.         }
  191.         $this->config['PHPTemplateDir'] or
  192.             $this->config['PHPTemplateDir'] = $blog_site_path .
  193.             DIRECTORY_SEPARATOR . 'templates';
  194.         $this->config['PHPCacheDir'] or
  195.             $this->config['PHPCacheDir'] = $blog_site_path .
  196.             DIRECTORY_SEPARATOR . 'cache';
  197.  
  198.         $ctx =& $this->context();
  199.         $ctx->template_dir = $this->config['PHPTemplateDir'];
  200.         $ctx->compile_dir = $ctx->template_dir . '_c';
  201.         $ctx->cache_dir = $this->config['PHPCacheDir'];
  202.     }
  203.  
  204.     /***
  205.      * Mainline handler function.
  206.      */
  207.     function view($blog_id = null) {
  208.         if ($this->debugging) {
  209.             require_once("MTUtil.php");
  210.         }
  211.         $blog_id or $blog_id = $this->blog_id;
  212.  
  213.         $ctx =& $this->context();
  214.         $this->init_plugins();
  215.         $ctx->caching = $this->caching;
  216.  
  217.         // Some defaults...
  218.         $mtdb =& $this->db();
  219.         $ctx->mt->db =& $mtdb;
  220.  
  221.         // Set up our customer error handler
  222.         $oldreporting = error_reporting(E_ALL ^ E_NOTICE);
  223.         set_error_handler(array(&$this, 'error_handler'));
  224.  
  225.         // User-specified request through request variable
  226.         $path = $this->request;
  227.  
  228.         // Apache request
  229.         if (!$path && $_SERVER['REQUEST_URI']) {
  230.             $path = $_SERVER['REQUEST_URI'];
  231.             // strip off any query string...
  232.             $path = preg_replace('/\?.*/', '', $path);
  233.             // strip any duplicated slashes...
  234.             $path = preg_replace('!/+!', '/', $path);
  235.         }
  236.  
  237.         // IIS request by error document...
  238.         if (!$path && (preg_match('/IIS/', $_SERVER['SERVER_SOFTWARE']))) {
  239.             // assume 404 handler
  240.             if (preg_match('/^\d+;(.*)$/', $_SERVER['QUERY_STRING'], $matches)) {
  241.                 $path = $matches[1];
  242.                 $path = preg_replace('!^http://[^/]+!', '', $path);
  243.                 if (preg_match('/\?(.+)?/', $path, $matches)) {
  244.                     $_SERVER['QUERY_STRING'] = $matches[1];
  245.                     $path = preg_replace('/\?.*$/', '', $path);
  246.                 }
  247.             }
  248.         }
  249.  
  250.         // now set the path so it may be queried
  251.         $this->request = $path;
  252.  
  253.         // When we are invoked as an ErrorDocument, the parameters are
  254.         // in the environment variables REDIRECT_*
  255.         if (isset($_SERVER['REDIRECT_QUERY_STRING'])) {
  256.             // todo: populate $_GET and QUERY_STRING with REDIRECT_QUERY_STRING
  257.             $_SERVER['QUERY_STRING'] = getenv('REDIRECT_QUERY_STRING');
  258.         }
  259.  
  260.         if (preg_match('/\.(\w+)$/', $path, $matches)) {
  261.             $req_ext = strtolower($matches[1]);
  262.         }
  263.  
  264.         $this->blog_id = $blog_id;
  265.  
  266.         $data =& $this->resolve_url($path);
  267.         if (!$data) {
  268.             // 404!
  269.             $this->http_error = 404;
  270.             header("HTTP/1.1 404 Not found");
  271.             header("Status: 404");
  272.             return $ctx->error("Page not found - $path", E_USER_ERROR);
  273.         }
  274.  
  275.         $info =& $data['fileinfo'];
  276.         $fid = $info['fileinfo_id'];
  277.         $at = $info['fileinfo_archive_type'];
  278.         $ts = $info['fileinfo_startdate'];
  279.         $tpl_id = $info['fileinfo_template_id'];
  280.         $cat = $info['fileinfo_category_id'];
  281.         $entry_id = $info['fileinfo_entry_id'];
  282.         $blog_id = $info['fileinfo_blog_id'];
  283.         $blog =& $data['blog'];
  284.         if ($at == 'index') {
  285.             $at = null;
  286.         }
  287.         $tts = $data['template']['template_modified_on'];
  288.         $tts = offset_time(datetime_to_timestamp($tts), $blog);
  289.         $ctx->stash('template_timestamp', $tts);
  290.  
  291.         $this->configure_paths($blog['blog_site_path']);
  292.  
  293.         // start populating our stash
  294.         $ctx->stash('blog_id', $blog_id);
  295.         $ctx->stash('blog', $blog);
  296.         if ($cat) {
  297.             $archive_category = $mtdb->fetch_category($cat);
  298.             $ctx->stash('category', $archive_category);
  299.             $ctx->stash('archive_category', $archive_category);
  300.         }
  301.         //$ctx->last_ts($info['template_modified_on']);
  302.  
  303.         // conditional get support...
  304.         if ($this->caching) {
  305.             $this->cache_modified_check = true;
  306.         }
  307.         if ($this->conditional) {
  308.             $last_ts = $blog['blog_children_modified_on'];
  309.             $last_modified = $ctx->_hdlr_date(array('ts' => $last_ts, 'format' => '%a, %d %b %Y %H:%M:%S GMT', 'language' => 'en', 'utc' => 1), $ctx);
  310.             $this->doConditionalGet($last_modified);
  311.         }
  312.  
  313.         $cache_id = $blog_id.';'.$path;
  314.         if (isset($ts)) {
  315.             require_once("MTUtil.php");
  316.             if ($at == 'Yearly') {
  317.                 $ts = substr($ts, 0, 4);
  318.             } elseif ($at == 'Monthly') {
  319.                 $ts = substr($ts, 0, 6);
  320.             } elseif ($at == 'Daily') {
  321.                 $ts = substr($ts, 0, 8);
  322.             }
  323.             if ($at == 'Weekly') {
  324.                 list($ts_start, $ts_end) = start_end_week($ts);
  325.             } else {
  326.                 list($ts_start, $ts_end) = start_end_ts($ts);
  327.             }
  328.             $ctx->stash('current_timestamp', $ts_start);
  329.             $ctx->stash('current_timestamp_end', $ts_end);
  330.         }
  331.         if (isset($at)) {
  332.             $ctx->stash('current_archive_type', $at);
  333.         }
  334.     
  335.         if (!$ctx->is_cached('mt:'.$tpl_id, $cache_id)) {
  336.             if (isset($entry_id) && ($entry_id) && ($at == 'Individual')) {
  337.                 $entry =& $mtdb->fetch_entry($entry_id);
  338.                 $ctx->stash('entry', $entry);
  339.                 $ctx->stash('current_timestamp', $entry['entry_created_on']);
  340.             }
  341.         }
  342.  
  343.         $this->http_error = 200;
  344.         header("HTTP/1.1 200 OK");
  345.         header("Status: 200");
  346.         // content-type header-- need to supplement with charset
  347.         $content_type = $this->mime_types['__default__'];
  348.         if ($req_ext && (isset($this->mime_types[$req_ext]))) {
  349.             $content_type = $this->mime_types[$req_ext];
  350.         }
  351.         if (isset($config['PublishCharset'])) {
  352.             $content_type .= '; charset=' . $config['PublishCharset'];
  353.         }
  354.         header("Content-Type: $content_type");
  355.  
  356.         $output = $ctx->fetch('mt:'.$tpl_id, $cache_id);
  357.  
  358.         //$last_ts = $ctx->last_ts();
  359.  
  360.         if ($this->debugging) {
  361.             $this->log("Queries: ".$mtdb->num_queries);
  362.             $this->log("Queries executed:");
  363.             $queries = $mtdb->savedqueries;
  364.             foreach ($queries as $q) {
  365.                 $this->log($q);
  366.             }
  367.             $this->log_dump();
  368.         }
  369.         restore_error_handler();
  370.         error_reporting($oldreporting);
  371.  
  372.         // finally, issue output
  373.         echo $output;
  374.     }
  375.  
  376.     function &resolve_url($path) {
  377.         $data =& $this->db->resolve_url($path, $this->blog_id);
  378.         return $data;
  379.     }
  380.  
  381.     function doConditionalGet($last_modified) {
  382.         // Thanks to Simon Willison...
  383.         //   http://simon.incutio.com/archive/2003/04/23/conditionalGet
  384.         // A PHP implementation of conditional get, see 
  385.         //   http://fishbowl.pastiche.org/archives/001132.html
  386.         $etag = '"'.md5($last_modified).'"';
  387.         // Send the headers
  388.         header("Last-Modified: $last_modified");
  389.         header("ETag: $etag");
  390.         // See if the client has provided the required headers
  391.         $if_modified_since = isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) ?
  392.             stripslashes($_SERVER['HTTP_IF_MODIFIED_SINCE']) :
  393.             false;
  394.         $if_none_match = isset($_SERVER['HTTP_IF_NONE_MATCH']) ?
  395.             stripslashes($_SERVER['HTTP_IF_NONE_MATCH']) : 
  396.             false;
  397.         if (!$if_modified_since && !$if_none_match) {
  398.             return;
  399.         }
  400.         // At least one of the headers is there - check them
  401.         if ($if_none_match && $if_none_match != $etag) {
  402.             return; // etag is there but doesn't match
  403.         }
  404.         if ($if_modified_since && $if_modified_since != $last_modified) {
  405.             return; // if-modified-since is there but doesn't match
  406.         }
  407.         // Nothing has changed since their last request - serve a 304 and exit
  408.         header('HTTP/1.1 304 Not Modified');
  409.         exit;
  410.     }
  411.  
  412.     function display($tpl, $cid = null) {
  413.         $ctx =& $this->context();
  414.         $this->init_plugins();
  415.         $blog =& $ctx->stash('blog');
  416.         if (!$blog) {
  417.             $db =& $this->db();
  418.             $ctx->mt->db =& $db;
  419.             $blog =& $db->fetch_blog($this->blog_id);
  420.             $ctx->stash('blog', $blog);
  421.             $ctx->stash('blog_id', $this->blog_id);
  422.             $this->configure_paths($blog['blog_site_path']);
  423.         }
  424.         return $ctx->display($tpl, $cid);
  425.     }
  426.  
  427.     function fetch($tpl, $cid = null) {
  428.         $ctx =& $this->context();
  429.         $this->init_plugins();
  430.         $blog =& $ctx->stash('blog');
  431.         if (!$blog) {
  432.             $db =& $this->db();
  433.             $ctx->mt->db =& $db;
  434.             $blog =& $db->fetch_blog($this->blog_id);
  435.             $ctx->stash('blog', $blog);
  436.             $ctx->stash('blog_id', $this->blog_id);
  437.             $this->configure_paths($blog['blog_site_path']);
  438.         }
  439.         return $ctx->fetch($tpl, $cid);
  440.     }
  441.  
  442.     function log_dump() {
  443.         if ($_SERVER['REMOTE_ADDR']) {
  444.             // web view...
  445.             echo "<div class=\"debug\" style=\"border:1px solid red; margin:0.5em; padding: 0 1em; text-align:left; background-color:#ddd; color:#000\"><pre>";
  446.             echo implode("\n", $this->log);
  447.             echo "</pre></div>\n\n";
  448.         } else {
  449.             // console view...
  450.             $stderr = fopen('php://stderr', 'w'); 
  451.             fwrite($stderr,implode("\n", $this->log)); 
  452.             echo (implode("\n", $this->log)); 
  453.             fclose($stderr);
  454.         }
  455.     }
  456.  
  457.     function error_handler($errno, $errstr, $errfile, $errline) {
  458.         if ($errno & (E_ALL ^ E_NOTICE)) {
  459.             $mtphpdir = $this->config['PHPDir'];
  460.             $ctx =& $this->context();
  461.             $ctx->stash('blog_id', $this->blog_id);
  462.             $ctx->stash('error_message', $errstr."<!-- file: $errfile; line: $errline; code: $errno -->");
  463.             $ctx->stash('error_code', $errno);
  464.             $http_error = $this->http_error;
  465.             if (!$http_error) {
  466.                 $http_error = 500;
  467.             }
  468.             $ctx->stash('http_error', $http_error);
  469.             $ctx->stash('error_file', $errfile);
  470.             $ctx->stash('error_line', $errline);
  471.             $ctx->template_dir = $mtphpdir . DIRECTORY_SEPARATOR . 'tmpl';
  472.             $ctx->caching = 0;
  473.             $ctx->stash('StaticWebPath', $this->config['StaticWebPath']);
  474.             $ctx->stash('PublishCharset', $this->config['PublishCharset']);
  475.             $charset = $this->config['PublishCharset'];
  476.             $out = $ctx->tag('Include', array('type' => 'dynamic_error'));
  477.             if (isset($out)) {
  478.                 header("Content-type: text/html; charset=".$charset);
  479.                 echo $out;
  480.             } else {
  481.                 header("HTTP/1.1 500 Server Error");
  482.                 header("Content-type: text/plain");
  483.                 echo "Error executing error template.";
  484.             }
  485.             exit;
  486.         }
  487.     }
  488.  
  489.     /***
  490.      * Retreives a context and rendering object.
  491.      */
  492.     function &context() {
  493.         static $ctx;
  494.         if (isset($ctx)) return $ctx;
  495.  
  496.         require_once('MTViewer.php');
  497.         $ctx = new MTViewer($this);
  498.         $ctx->mt =& $this;
  499.         $mtphpdir = $this->config['PHPDir'];
  500.         $mtlibdir = $this->config['PHPLibDir'];
  501.         $ctx->compile_check = 1;
  502.         $ctx->caching = false;
  503.         $ctx->plugins_dir[] = $mtlibdir;
  504.         $ctx->plugins_dir[] = $mtphpdir . DIRECTORY_SEPARATOR . "plugins";
  505.         if ($this->debugging) {
  506.             $ctx->debugging_ctrl = 'URL';
  507.             $ctx->debug_tpl = $mtphpdir . DIRECTORY_SEPARATOR .
  508.                 'extlib' . DIRECTORY_SEPARATOR .
  509.                 'smarty' . DIRECTORY_SEPARATOR .
  510.                 'debug.tpl';
  511.         }
  512.         if (isset($this->config['SafeMode']) && ($this->config['SafeMode'])) {
  513.             // disable PHP support
  514.             $ctx->php_handling = SMARTY_PHP_REMOVE;
  515.         }
  516.         return $ctx;
  517.     }
  518.  
  519.     function log($msg = null) {
  520.         $this->log[] = $msg;
  521.     }
  522.  
  523.     function translate_templatized_item($str) {
  524.         // todo: run through translation layer
  525.         return $str[1];
  526.     }
  527.  
  528.     function translate_templatized($tmpl) {
  529.         $cb = array($this, 'translate_templatized_item');
  530.         $out = preg_replace_callback('/<MT_TRANS phrase="(.+?)">/', $cb, $tmpl);
  531.         return $out;
  532.     }
  533. }
  534.  
  535. function is_valid_email($addr) {
  536.     if (preg_match('/[ |\t|\r|\n]*\"?([^\"]+\"?@[^ <>\t]+\.[^ <>\t][^ <>\t]+)[ |\t|\r|\n]*/', $addr, $matches)) {
  537.         return $matches[1];
  538.     } else {
  539.         return 0;
  540.     }
  541. }
  542.  
  543. $spam_protect_map = array(':' => ':', '@' => '@', '.' => '.');
  544. function spam_protect($str) {
  545.     global $spam_protect_map;
  546.     return strtr($str, $spam_protect_map);
  547. }
  548.  
  549. function datetime_to_timestamp($dt) {
  550.     $dt = preg_replace('/[^0-9]/', '', $dt);
  551.     $ts = mktime(substr($dt, 8, 2), substr($dt, 10, 2), substr($dt, 12, 2), substr($dt, 4, 2), substr($dt, 6, 2), substr($dt, 0, 4));
  552.     return $ts;
  553. }
  554.  
  555. function offset_time($ts, $blog = null, $dir = null) {
  556.     if (isset($blog)) {
  557.         if (!is_array($blog)) {
  558.             global $mt;
  559.             $blog = $mt->db->fetch_blog($blog);
  560.         }
  561.         $offset = $blog['blog_server_offset'];
  562.     } else {
  563.         global $mt;
  564.         $offset = $mt->config['TimeOffset'];
  565.     }
  566.     intval($offset) or $offset = 0;
  567.     $tsa = localtime($ts);
  568.  
  569.     if ($tsa[8]) {  // daylight savings offset
  570.         $offset++;
  571.     }
  572.     if ($dir == '-') {
  573.         $offset *= -1;
  574.     }
  575.     $ts += $offset * 3600;
  576.     return $ts;
  577. }
  578. ?>
  579.